﻿using System.Linq;
using LukasKopenec.LocalizationSupport;
using Notoric.Commanding.CommandBase;

namespace Notoric.ViewModel
{
    /// <summary>
    /// Implements an undoable command for creating a new text section.
    /// </summary>
    /// <remarks>
    /// Input Parameters:
    /// <list type="table">
    /// <listheader>
    /// <term>
    ///     Name
    /// </term>
    /// <description>
    ///     Description
    /// </description>
    /// </listheader>
    /// <item>
    /// <term>
    ///     Owner (<see cref="Elements.Page"/>)
    /// </term>
    /// <description>
    ///     The page that will own the created section.
    /// </description>
    /// </item>
    /// <item>
    /// <term>
    ///     InteriorCreator (<see cref="Model.Elements.SectionInteriorCreator"/>)
    /// </term>
    /// <description>
    ///     The method that will create the interior of the created section.<br/>
    ///     Default value is <see cref="Model.Elements.DefaultImageSectionInterior.CreateInstance"/>
    /// </description>
    /// </item>
    /// </list>
    /// Output Parameters:
    /// <list type="table">
    /// <listheader>
    /// <term>
    ///     Name
    /// </term>
    /// <description>
    ///     Description
    /// </description>
    /// </listheader>
    /// <item>
    /// <term>
    ///     CreatedSection (<see cref="Elements.TextSection"/>)
    /// </term>
    /// <description>
    ///     The section created by this command.
    /// </description>
    /// </item>
    /// </list>
    /// The command can execute if all of its input parameters are set.
    /// </remarks>
    public class NewTextSectionCommand : UndoableCommandBase
    {
        #region Constructors

        /// <summary>
        /// Creates a new <see cref="NewTextSectionCommand"/> instance.
        /// </summary>
        /// <param name="undoStack">
        /// <para>
        /// Type: <see cref="CommandStack"/>
        /// </para>
        /// <para>
        /// The command stack where the command will be put after its execution.
        /// </para>
        /// </param>
        /// <param name="redoStack">
        /// <para>
        /// Type: <see cref="CommandStack"/>
        /// </para>
        /// <para>
        /// The command stack where the command will be put whe it has been undone.
        /// </para>
        /// </param>
        public NewTextSectionCommand(CommandStack undoStack, CommandStack redoStack)
            : base(undoStack, redoStack)
        {
            AddParameter<Elements.Page>("Owner", ParameterDirection.In);
            AddParameter<Model.Elements.SectionInteriorCreator>("InteriorCreator", ParameterDirection.In);
            AddParameter<Elements.TextSection>("CreatedSection", ParameterDirection.Out);

            InteriorCreator = Model.Elements.RtfTextSectionInteriorElement.Create;

            Name = (string)LocalizationManager.GetValue("Commands.Names.NewTextSection");
        }

        #endregion

        #region Command Logic

        /// <inheritdoc/>
        protected override void CommandOperation(object parameter)
        {
            var modelSection = ((Model.Elements.PageElement)Owner.AdaptedElement).CreateTextSection(InteriorCreator);
            CreatedSection = (Elements.TextSection)Owner.Sections.First(section => section.AdaptedElement == modelSection);

            Owner.FindOwner<Elements.Project>().IsModified = true;
        }

        /// <inheritdoc/>
        protected override void RedoOperation()
        {
            ((Model.Elements.PageElement)Owner.AdaptedElement).Sections.Add((Model.Elements.SectionElement)CreatedSection.AdaptedElement);
            var vmSection = Owner.Sections.First(s => s.AdaptedElement == CreatedSection.AdaptedElement);
            Owner.Sections[Owner.Sections.IndexOf(vmSection)] = CreatedSection;

            Owner.FindOwner<Elements.Project>().IsModified = true;
        }

        /// <inheritdoc/>
        protected override void UndoOperation()
        {
            Owner.ClearSelection();
            ((Model.Elements.PageElement)Owner.AdaptedElement).Sections.Remove((Model.Elements.SectionElement)CreatedSection.AdaptedElement);

            Owner.FindOwner<Elements.Project>().IsModified = true;
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets the created section.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="Elements.TextSection"/>
        /// </para>
        /// <para>
        /// The section created by this command.<br/>
        /// This property wraps the "CreatedSection" command parameter.
        /// </para>
        /// </value>
        public Elements.TextSection CreatedSection
        {
            get { return GetParameterValue<Elements.TextSection>("CreatedSection"); }
            private set { SetParameterValue<Elements.TextSection>("CreatedSection", value); }
        }

        /// <summary>
        /// Gets or sets the method that will create the interior of the section.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="Model.Elements.SectionInteriorCreator"/>
        /// </para>
        /// <para>
        /// The method that will create the interior of the section.<br/>
        /// This property wraps the "InteriorCreator" command parameter.
        /// </para>
        /// </value>
        public Model.Elements.SectionInteriorCreator InteriorCreator
        {
            get { return GetParameterValue<Model.Elements.SectionInteriorCreator>("InteriorCreator"); }
            set { SetParameterValue<Model.Elements.SectionInteriorCreator>("InteriorCreator", value); }
        }

        /// <summary>
        /// Gets or sets the page that will own the created section.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="Elements.Page"/>
        /// </para>
        /// <para>
        /// The page that will own the created section.<br/>
        /// This property wraps the "Owner" command parameter.
        /// </para>
        /// </value>
        public Elements.Page Owner
        {
            get { return GetParameterValue<Elements.Page>("Owner"); }
            set { SetParameterValue<Elements.Page>("Owner", value); }
        }

        #endregion
    }
}
